#ifndef __I2C__H__
#define __I2C__H__

#include "cst92f2x.h"
#include "types.h"
#include "gpio.h"
#include "log.h"
#include "OSAL.h"
#include "pwrmgr.h"
#include <string.h>


#define ADDR_I2C0_CON 0x40005000
#define ADDR_I2C0_TAR 0x40005004
#define ADDR_I2C0_SAR 0x40005008
#define ADDR_I2C0_HS_MADDR 0x4000500C
#define ADDR_I2C0_DATA_CMD 0x40005010
#define ADDR_I2C0_SS_SCL_HCNT 0x40005014
#define ADDR_I2C0_SS_SCL_LCNT 0x40005018
#define ADDR_I2C0_FS_SCL_HCNT 0x4000501C
#define ADDR_I2C0_FS_SCL_LCNT 0x40005020
#define ADDR_I2C0_HS_SCL_HCNT 0x40005024
#define ADDR_I2C0_HS_SCL_LCNT 0x40005028
#define ADDR_I2C0_INTR_STAT 0x4000502C
#define ADDR_I2C0_INTR_MASK 0x40005030
#define ADDR_I2C0_RAW_INTR_STAT 0x40005034
#define ADDR_I2C0_RX_TL 0x40005038
#define ADDR_I2C0_TX_TL 0x4000503C
#define ADDR_I2C0_CLR_INTR 0x40005040
#define ADDR_I2C0_CLR_UNDER 0x40005044
#define ADDR_I2C0_CLR_RX_OVER 0x40005048
#define ADDR_I2C0_CLR_TX_OVER 0x4000504C
#define ADDR_I2C0_CLR_RD_REG 0x40005050
#define ADDR_I2C0_CLR_TX_ABRT 0x40005054
#define ADDR_I2C0_CLR_RX_DONE 0x40005058
#define ADDR_I2C0_CLR_ACTIVITY 0x4000505C
#define ADDR_I2C0_CLR_STOP_DET 0x40005060
#define ADDR_I2C0_CLR_START_DET 0x40005064
#define ADDR_I2C0_CLR_GEN_CALL 0x40005068
#define ADDR_I2C0_ENABLE 0x4000506C
#define ADDR_I2C0_STATUS 0x40005070
#define ADDR_I2C0_TXFLR 0x40005074
#define ADDR_I2C0_RXFLR 0x40005078
#define ADDR_I2C0_SDA_HOLD 0x4000507C
#define ADDR_I2C0_TX_ABRT_SOURCE 0x40005080
#define ADDR_I2C0_SLV_DATA_NACK_ONLY 0x40005084
#define ADDR_I2C0_DMA_CR 0x40005088
#define ADDR_I2C0_DMA_TDLR 0x4000508C
#define ADDR_I2C0_DMA_RDLR 0x40005090
#define ADDR_I2C0_SDA_SETUP 0x40005094
#define ADDR_I2C0_ACK_GENERAL_CALL 0x40005098
#define ADDR_I2C0_ENABLE_STATUS 0x4000509C
#define ADDR_I2C0_FS_SPKLEN 0x400050A0
#define ADDR_I2C0_HS_SPKLEN 0x400050A4

#define ADDR_I2C1_CON 0x40005800
#define ADDR_I2C1_TAR 0x40005804
#define ADDR_I2C1_SAR 0x40005808
#define ADDR_I2C1_HS_MADDR 0x4000580C
#define ADDR_I2C1_DATA_CMD 0x40005810
#define ADDR_I2C1_SS_SCL_HCNT 0x40005814
#define ADDR_I2C1_SS_SCL_LCNT 0x40005818
#define ADDR_I2C1_FS_SCL_HCNT 0x4000581C
#define ADDR_I2C1_FS_SCL_LCNT 0x40005820
#define ADDR_I2C1_HS_SCL_HCNT 0x40005824
#define ADDR_I2C1_HS_SCL_LCNT 0x40005828
#define ADDR_I2C1_INTR_STAT 0x4000582C
#define ADDR_I2C1_INTR_MASK 0x40005830
#define ADDR_I2C1_RAW_INTR_STAT 0x40005834
#define ADDR_I2C1_RX_TL 0x40005838
#define ADDR_I2C1_TX_TL 0x4000583C
#define ADDR_I2C1_CLR_INTR 0x40005840
#define ADDR_I2C1_CLR_UNDER 0x40005844
#define ADDR_I2C1_CLR_RX_OVER 0x40005848
#define ADDR_I2C1_CLR_TX_OVER 0x4000584C
#define ADDR_I2C1_CLR_RD_REG 0x40005850
#define ADDR_I2C1_CLR_TX_ABRT 0x40005854
#define ADDR_I2C1_CLR_RX_DONE 0x40005858
#define ADDR_I2C1_CLR_ACTIVITY 0x4000585C
#define ADDR_I2C1_CLR_STOP_DET 0x40005860
#define ADDR_I2C1_CLR_START_DET 0x40005864
#define ADDR_I2C1_CLR_GEN_CALL 0x40005868
#define ADDR_I2C1_ENABLE 0x4000586C
#define ADDR_I2C1_STATUS 0x40005870
#define ADDR_I2C1_TXFLR 0x40005874
#define ADDR_I2C1_RXFLR 0x40005878
#define ADDR_I2C1_SDA_HOLD 0x4000587C
#define ADDR_I2C1_TX_ABRT_SOURCE 0x40005880
#define ADDR_I2C1_SLV_DATA_NACK_ONLY 0x40005884
#define ADDR_I2C1_DMA_CR 0x40005888
#define ADDR_I2C1_DMA_TDLR 0x4000588C
#define ADDR_I2C1_DMA_RDLR 0x40005890
#define ADDR_I2C1_SDA_SETUP 0x40005894
#define ADDR_I2C1_ACK_GENERAL_CALL 0x40005898
#define ADDR_I2C1_ENABLE_STATUS 0x4000589C
#define ADDR_I2C1_FS_SPKLEN 0x400058A0
#define ADDR_I2C1_HS_SPKLEN 0x400058A4

#define REG_I2C0_CON (*((volatile unsigned int *)(ADDR_I2C0_CON)))
#define REG_I2C0_TAR (*((volatile unsigned int *)(ADDR_I2C0_TAR)))
#define REG_I2C0_SAR (*((volatile unsigned int *)(ADDR_I2C0_SAR)))
#define REG_I2C0_HS_MADDR (*((volatile unsigned int *)(ADDR_I2C0_HS_MADDR)))
#define REG_I2C0_DATA_CMD (*((volatile unsigned int *)(ADDR_I2C0_DATA_CMD)))
#define REG_I2C0_SS_SCL_HCNT (*((volatile unsigned int *)(ADDR_I2C0_SS_SCL_HCNT)))
#define REG_I2C0_SS_SCL_LCNT (*((volatile unsigned int *)(ADDR_I2C0_SS_SCL_LCNT)))
#define REG_I2C0_FS_SCL_HCNT (*((volatile unsigned int *)(ADDR_I2C0_FS_SCL_HCNT)))
#define REG_I2C0_FS_SCL_LCNT (*((volatile unsigned int *)(ADDR_I2C0_FS_SCL_LCNT)))
#define REG_I2C0_HS_SCL_HCNT (*((volatile unsigned int *)(ADDR_I2C0_HS_SCL_HCNT)))
#define REG_I2C0_HS_SCL_LCNT (*((volatile unsigned int *)(ADDR_I2C0_HS_SCL_LCNT)))
#define REG_I2C0_INTR_STAT (*((volatile unsigned int *)(ADDR_I2C0_INTR_STAT)))
#define REG_I2C0_INTR_MASK (*((volatile unsigned int *)(ADDR_I2C0_INTR_MASK)))
#define REG_I2C0_RAW_INTR_STAT (*((volatile unsigned int *)(ADDR_I2C0_RAW_INTR_STAT)))
#define REG_I2C0_RX_TL (*((volatile unsigned int *)(ADDR_I2C0_RX_TL)))
#define REG_I2C0_TX_TL (*((volatile unsigned int *)(ADDR_I2C0_TX_TL)))
#define REG_I2C0_CLR_INTR (*((volatile unsigned int *)(ADDR_I2C0_CLR_INTR)))
#define REG_I2C0_CLR_UNDER (*((volatile unsigned int *)(ADDR_I2C0_CLR_UNDER)))
#define REG_I2C0_CLR_RX_OVER (*((volatile unsigned int *)(ADDR_I2C0_CLR_RX_OVER)))
#define REG_I2C0_CLR_TX_OVER (*((volatile unsigned int *)(ADDR_I2C0_CLR_TX_OVER)))
#define REG_I2C0_CLR_RD_REG (*((volatile unsigned int *)(ADDR_I2C0_CLR_RD_REG)))
#define REG_I2C0_CLR_TX_ABRT (*((volatile unsigned int *)(ADDR_I2C0_CLR_TX_ABRT)))
#define REG_I2C0_CLR_RX_DONE (*((volatile unsigned int *)(ADDR_I2C0_CLR_RX_DONE)))
#define REG_I2C0_CLR_ACTIVITY (*((volatile unsigned int *)(ADDR_I2C0_CLR_ACTIVITY)))
#define REG_I2C0_CLR_STOP_DET (*((volatile unsigned int *)(ADDR_I2C0_CLR_STOP_DET)))
#define REG_I2C0_CLR_START_DET (*((volatile unsigned int *)(ADDR_I2C0_CLR_START_DET)))
#define REG_I2C0_CLR_GEN_CALL (*((volatile unsigned int *)(ADDR_I2C0_CLR_GEN_CALL)))
#define REG_I2C0_ENABLE (*((volatile unsigned int *)(ADDR_I2C0_ENABLE)))
#define REG_I2C0_STATUS (*((volatile unsigned int *)(ADDR_I2C0_STATUS)))
#define REG_I2C0_TXFLR (*((volatile unsigned int *)(ADDR_I2C0_TXFLR)))
#define REG_I2C0_RXFLR (*((volatile unsigned int *)(ADDR_I2C0_RXFLR)))
#define REG_I2C0_SDA_HOLD (*((volatile unsigned int *)(ADDR_I2C0_SDA_HOLD)))
#define REG_I2C0_TX_ABRT_SOURCE (*((volatile unsigned int *)(ADDR_I2C0_TX_ABRT_SOURCE)))
#define REG_I2C0_SLV_DATA_NACK_ONLY (*((volatile unsigned int *)(ADDR_I2C0_SLV_DATA_NACK_ONLY)))
#define REG_I2C0_DMA_CR (*((volatile unsigned int *)(ADDR_I2C0_DMA_CR)))
#define REG_I2C0_DMA_TDLR (*((volatile unsigned int *)(ADDR_I2C0_DMA_TDLR)))
#define REG_I2C0_DMA_RDLR (*((volatile unsigned int *)(ADDR_I2C0_DMA_RDLR)))
#define REG_I2C0_SDA_SETUP (*((volatile unsigned int *)(ADDR_I2C0_SDA_SETUP)))
#define REG_I2C0_ACK_GENERAL_CALL (*((volatile unsigned int *)(ADDR_I2C0_ACK_GENERAL_CALL)))
#define REG_I2C0_ENABLE_STATUS (*((volatile unsigned int *)(ADDR_I2C0_ENABLE_STATUS)))
#define REG_I2C0_FS_SPKLEN (*((volatile unsigned int *)(ADDR_I2C0_FS_SPKLEN)))
#define REG_I2C0_HS_SPKLEN (*((volatile unsigned int *)(ADDR_I2C0_HS_SPKLEN)))

#define REG_I2C1_CON (*((volatile unsigned int *)(ADDR_I2C1_CON)))
#define REG_I2C1_TAR (*((volatile unsigned int *)(ADDR_I2C1_TAR)))
#define REG_I2C1_SAR (*((volatile unsigned int *)(ADDR_I2C1_SAR)))
#define REG_I2C1_HS_MADDR (*((volatile unsigned int *)(ADDR_I2C1_HS_MADDR)))
#define REG_I2C1_DATA_CMD (*((volatile unsigned int *)(ADDR_I2C1_DATA_CMD)))
#define REG_I2C1_SS_SCL_HCNT (*((volatile unsigned int *)(ADDR_I2C1_SS_SCL_HCNT)))
#define REG_I2C1_SS_SCL_LCNT (*((volatile unsigned int *)(ADDR_I2C1_SS_SCL_LCNT)))
#define REG_I2C1_FS_SCL_HCNT (*((volatile unsigned int *)(ADDR_I2C1_FS_SCL_HCNT)))
#define REG_I2C1_FS_SCL_LCNT (*((volatile unsigned int *)(ADDR_I2C1_FS_SCL_LCNT)))
#define REG_I2C1_HS_SCL_HCNT (*((volatile unsigned int *)(ADDR_I2C1_HS_SCL_HCNT)))
#define REG_I2C1_HS_SCL_LCNT (*((volatile unsigned int *)(ADDR_I2C1_HS_SCL_LCNT)))
#define REG_I2C1_INTR_STAT (*((volatile unsigned int *)(ADDR_I2C1_INTR_STAT)))
#define REG_I2C1_INTR_MASK (*((volatile unsigned int *)(ADDR_I2C1_INTR_MASK)))
#define REG_I2C1_RAW_INTR_STAT (*((volatile unsigned int *)(ADDR_I2C1_RAW_INTR_STAT)))
#define REG_I2C1_RX_TL (*((volatile unsigned int *)(ADDR_I2C1_RX_TL)))
#define REG_I2C1_TX_TL (*((volatile unsigned int *)(ADDR_I2C1_TX_TL)))
#define REG_I2C1_CLR_INTR (*((volatile unsigned int *)(ADDR_I2C1_CLR_INTR)))
#define REG_I2C1_CLR_UNDER (*((volatile unsigned int *)(ADDR_I2C1_CLR_UNDER)))
#define REG_I2C1_CLR_RX_OVER (*((volatile unsigned int *)(ADDR_I2C1_CLR_RX_OVER)))
#define REG_I2C1_CLR_TX_OVER (*((volatile unsigned int *)(ADDR_I2C1_CLR_TX_OVER)))
#define REG_I2C1_CLR_RD_REG (*((volatile unsigned int *)(ADDR_I2C1_CLR_RD_REG)))
#define REG_I2C1_CLR_TX_ABRT (*((volatile unsigned int *)(ADDR_I2C1_CLR_TX_ABRT)))
#define REG_I2C1_CLR_RX_DONE (*((volatile unsigned int *)(ADDR_I2C1_CLR_RX_DONE)))
#define REG_I2C1_CLR_ACTIVITY (*((volatile unsigned int *)(ADDR_I2C1_CLR_ACTIVITY)))
#define REG_I2C1_CLR_STOP_DET (*((volatile unsigned int *)(ADDR_I2C1_CLR_STOP_DET)))
#define REG_I2C1_CLR_START_DET (*((volatile unsigned int *)(ADDR_I2C1_CLR_START_DET)))
#define REG_I2C1_CLR_GEN_CALL (*((volatile unsigned int *)(ADDR_I2C1_CLR_GEN_CALL)))
#define REG_I2C1_ENABLE (*((volatile unsigned int *)(ADDR_I2C1_ENABLE)))
#define REG_I2C1_STATUS (*((volatile unsigned int *)(ADDR_I2C1_STATUS)))
#define REG_I2C1_TXFLR (*((volatile unsigned int *)(ADDR_I2C1_TXFLR)))
#define REG_I2C1_RXFLR (*((volatile unsigned int *)(ADDR_I2C1_RXFLR)))
#define REG_I2C1_SDA_HOLD (*((volatile unsigned int *)(ADDR_I2C1_SDA_HOLD)))
#define REG_I2C1_TX_ABRT_SOURCE (*((volatile unsigned int *)(ADDR_I2C1_TX_ABRT_SOURCE)))
#define REG_I2C1_SLV_DATA_NACK_ONLY (*((volatile unsigned int *)(ADDR_I2C1_SLV_DATA_NACK_ONLY)))
#define REG_I2C1_DMA_CR (*((volatile unsigned int *)(ADDR_I2C1_DMA_CR)))
#define REG_I2C1_DMA_TDLR (*((volatile unsigned int *)(ADDR_I2C1_DMA_TDLR)))
#define REG_I2C1_DMA_RDLR (*((volatile unsigned int *)(ADDR_I2C1_DMA_RDLR)))
#define REG_I2C1_SDA_SETUP (*((volatile unsigned int *)(ADDR_I2C1_SDA_SETUP)))
#define REG_I2C1_ACK_GENERAL_CALL (*((volatile unsigned int *)(ADDR_I2C1_ACK_GENERAL_CALL)))
#define REG_I2C1_ENABLE_STATUS (*((volatile unsigned int *)(ADDR_I2C1_ENABLE_STATUS)))
#define REG_I2C1_FS_SPKLEN (*((volatile unsigned int *)(ADDR_I2C1_FS_SPKLEN)))
#define REG_I2C1_HS_SPKLEN (*((volatile unsigned int *)(ADDR_I2C1_HS_SPKLEN)))

#define  I2C_RX_FIFO_FULL()          ((I2Cx->IC_STATUS & 0x10)==0x10)
#define  I2C_RX_FIFO_NOT_EMPTY()     ((I2Cx->IC_STATUS & 0x08)==0x08)
#define  I2C_TX_FIFO_EMPTY()         ((I2Cx->IC_STATUS & 0x04)==0x04)
#define  I2C_TX_FIFO_NOT_FULL()      ((I2Cx->IC_STATUS & 0x02)==0x02)
#define  I2C_NUMBER_DATA_RX_FIFO()   I2Cx->IC_RXFLR
#define  I2C_NUMBER_DATA_TX_FIFO()   I2Cx->IC_TXFLR


/**
* @def
* @brief: I2C Interrupt MASK bit
* @Details
*/
#define I2C_MASK_RX_UNDER 		0x0001
#define I2C_MASK_RX_OVER 		0x0002
#define I2C_MASK_RX_FULL 		0x0004
#define I2C_MASK_TX_OVER 		0x0008
#define I2C_MASK_TX_EMPTY 		0x0010
#define I2C_MASK_RD_REQ 		0x0020
#define I2C_MASK_TX_ABRT 		0x0040
#define I2C_MASK_RX_DONE 		0x0080
#define I2C_MASK_ACTIVITY 		0x0100
#define I2C_MASK_STOP_DET 		0x0200
#define I2C_MASK_START_DET 		0x0400
#define I2C_MASK_GEN_CALL 		0x0800

/**
* @def
* @brief: I2C status bit
* @Details
*/
#define I2C_STATUS_ACTIVITY 	0x0001
#define I2C_STATUS_TFNF 		0x0002
#define I2C_STATUS_TFE 			0x0004
#define I2C_STATUS_RFNE 		0x0008
#define I2C_STATUS_RFF 			0x0010
#define I2C_STATUS_MST_ACTIVITY 0x0020
#define I2C_STATUS_SLV_ACTIVITY 0x0040

#define I2C_FIFO_SIZE 			8

/*******************************************************************************
    @ Module               :  Macro Define
    @ Description    :  I2C_SLAVE_ADDR_DEF ---- as slave mode
                     I2C_MASTER_ADDR_DEF --- as master mode addressing device
*******************************************************************************/
#define  I2C_SLAVE_ADDR_DEF           0x10
#define  I2C_MASTER_ADDR_DEF          I2C_SLAVE_ADDR_DEF

/**
* @enum I2cRole_t
* @brief i2c role struct
*/
typedef enum
{
	I2C_ROLE_SLAVE = 0, //!< i2c slave
	I2C_ROLE_MASTER,	//!< i2c master
} I2cRole_t;

/**
* @enum I2cClock_t
* @brief i2c clock struct
*/
typedef enum
{
	I2C_CLOCK_100K = 0, //!< i2c clock 100k
	I2C_CLOCK_400K,		//!< i2c clock 400k
} I2cClock_t;

/**
* @enum I2cAddressBit_t
* @brief i2c address bit struct
*/
typedef enum
{
	I2C_ADDRESS_BIT_7 = 0,  //!< i2c address 7 bit
	I2C_ADDRESS_BIT_10 = 1, //!< i2c address 10 bit
} I2cAddressBit_t;

/**
* @enum I2cEvtType_t
* @brief i2c event type 
*/
typedef enum{
	I2C_EVT_TYPE_RD_REQ = 1,		// only in slave mode, it's valid
	I2C_EVT_TYPE_TRANSFER_COMPLETED,
	I2C_EVT_TYPE_ERROR
} I2cEvtType_t;

/**
* @enum I2cWorkMode_t
* @brief enum type about i2c work mode
*/
typedef enum {
	I2C_WORK_MODE_POLLING = 0,
	I2C_WORK_MODE_INT = 1,
}I2cWorkMode_t;

/**
* @enum I2cEvt_t
* @brief i2c event struct
*/
typedef struct
{
	uint8_t type;   	//!< i2c event type, the value is from I2cEvtType_t
	uint8_t*  data;
    uint8_t   len;
} I2cEvt_t;

/**
* @enum
* @brief i2c event callback
*/
typedef void (*pfnI2cHdlCB_t)(I2cEvt_t *Evt);

/**
* @enum I2cCfg_t
* @brief i2c config struct
*/
typedef struct
{
	GpioPin_t i2cScl;			   //!< i2c scl pin
	GpioPin_t i2cSda;			   //!< i2c sda pin
	I2cRole_t i2cRole;			   //!< i2c role
	I2cClock_t i2cClock;		   //!< i2c clock
	I2cAddressBit_t i2cAddressBit; //!< i2c address bit
	uint16_t i2cAddress;		   //!< i2c work in master ,i2cAddress is target address;i2c work in slave,i2cAddress is slave address;
	I2cWorkMode_t i2cWorkMode;	 	//!< i2c work mode, polling or int, it's valid when role is master
	pfnI2cHdlCB_t evtHdlCB;		   //!< i2c event callback function
} I2cCfg_t;

ErrCode_t HalI2cInit(AP_I2C_TypeDef *I2Cx, I2cCfg_t *cfg);
ErrCode_t HalI2cMasterWrite(AP_I2C_TypeDef *I2Cx, uint16_t devAddr, uint32_t reg,uint8_t regLen, uint8_t *txBuf, uint16_t txBufLen);
ErrCode_t HalI2cMasterRead(AP_I2C_TypeDef *I2Cx, uint16_t devAddr, uint32_t reg,uint8_t regLen, uint8_t *rxBuf, uint16_t rxBufLen);
ErrCode_t HalI2cGetTransferComplete(AP_I2C_TypeDef *I2Cx);


#endif
